home *** CD-ROM | disk | FTP | other *** search
/ X User Tools / X User Tools (O'Reilly and Associates)(1994).ISO / sources / xbmbrows / xbmbro31.z / xbmbro31 / xbmbrowser3.1 / bitmaps.c next >
C/C++ Source or Header  |  1993-08-05  |  14KB  |  437 lines

  1. /********************************************************************\
  2. **                             _________________________________    **
  3. **   A n t h o n y            |________    __    __    _________|   **
  4. **                                     |  |o_|  |o_|  |             **
  5. **           T h y s s e n           __|   __    __   |__           **
  6. **                                __|   __|  |  |  |__   |__        **
  7. **  `` Dragon Computing! ''    __|   __|     |  |     |__   |__     **
  8. **                            |_____|        |__|        |_____|    **
  9. **                                                                  **
  10. \********************************************************************/
  11. /* 
  12. ** bitmap.c
  13. **
  14. **   This module represents a complete re-write of the data structures used
  15. ** by xbmbrowser to orginise the bitmaps and widgets. These structures
  16. ** although initially created in get_files(), are static to this module.
  17. ** Previously the data structure did not allow for expandsion of bitmap
  18. ** types, storage of pixel colors used, or for checks on modification
  19. ** times.
  20. **                         Anthony Thyssen <anthony@dragon.cit.gu.edu.au>
  21. */
  22. #include "xbmbrowser.h"
  23.  
  24. static Item   *new_file_list = NULL; /* new file list for merging */
  25. static Item   *file_list = NULL;     /* current list of files (& dir) */
  26.  
  27. static Widget *widget_array = NULL;  /* array of widgets available to use */
  28. static int     allocated = 0;        /* number of widgets in above array */
  29. static int     managed = 0;          /* number of widgets being managed */
  30.  
  31. static int file_counts[(int)NumFileTypes]; /* count of the various file types */
  32.  
  33. /*--------------------------------------------------------------------------*/
  34.  
  35. build_dirMenu()
  36. /*  Build the dirMenu from the just read in filelist. It is in this module
  37. ** only because it doesn't seem to fit in other modules.
  38. */
  39. {
  40.   static char *list[256];
  41.   int          list_offset = 0;
  42.   Item        *item = new_file_list;
  43.  
  44.   list[list_offset++] = "/";
  45.   list[list_offset++] = "~/";
  46.  
  47.   /* add to the menu any name in the file list that is a directory */
  48.   while( item != NULL ) {
  49.     if( item->type == Dir )
  50.          list[list_offset++] = item->fname;
  51.     item = item->next;
  52.   }
  53.   list[list_offset] = NULL;
  54.   XtVaSetValues(dirList,XtNdefaultColumns,(XtArgVal)(list_offset/25)+1,NULL);
  55.   XawListChange(dirList,list,0,0,True);
  56. }
  57.  
  58. /*--------------------------------------------------------------------------*/
  59.  
  60. Item *
  61. alloc_item()
  62. /* allocate and default a file item */
  63. {
  64.   Item *item = (Item *) malloc( sizeof(Item) );
  65.  
  66.   item->fname[0] = '\0';
  67.   item->type   = Bad;
  68.   item->bitmap = None;
  69.   item->index  = -1;
  70.   item->next   = NULL;
  71.  
  72.   return item;
  73. }
  74.  
  75.  
  76. Item *
  77. free_item(item)
  78. /* free the item and any aspect about that item. This is the ONLY place
  79. ** where bitmaps are to be freed. Return the next item in list!
  80. */
  81.   Item *item;
  82. {
  83.   Item *next = item->next;
  84.  
  85.   if( item->bitmap != None ) { /* bitmap to be freed ? */
  86.     if( item->index != -1 ) {
  87.       /* remove from bitmap from widget
  88.       ** NOTE: for some reason if the bitmap used by the widget is
  89.       ** set to `None', the XFreePixmap following will coredump!
  90.       */
  91.       XtVaSetValues(widget_array[item->index],
  92.                          XtNbitmap, (XtArgVal)None,  /* None */
  93.                          XtNlabel,  (XtArgVal)NULL,  NULL);
  94.     }
  95.     XFreePixmap(XtDisplay(toplevel), item->bitmap );
  96. #ifdef DO_XPMS
  97.     if( item->type == Xpm ) {
  98.       /* free colors and attributes used by pixmap */
  99.       /* PROBLEM -- what if color is used by another pixmap ? */
  100. #if 0
  101.       XFreeColors(XtDisplay(toplevel),
  102.                    DefaultColormapOfScreen(XtScreen(toplevel)),
  103.                    item->attr.pixels, item->attr.npixels, AllPlanes);
  104. #endif
  105.       XpmFreeAttributes((XpmAttributes *)&item->attr);
  106.     }
  107. #endif
  108.   }
  109.   free( item );
  110.  
  111.   return next;
  112. }
  113.  
  114. static int
  115. read_bitmap(item)
  116. /* attempt to read a bitmap for the item given -- return TRUE if success */
  117.   Item *item;
  118.   int i, status;   /* junk integer, size of icon, return status */
  119.   unsigned int x, y;
  120. #ifdef DO_XPMS
  121.   Pixmap m;              /* junk pixmap mask */
  122. #endif
  123.  
  124.   if( item->type != File )  /* if a not a file -- it can't be a bitmap */
  125.     return FALSE;
  126.  
  127.   /* first try for a X Bitmap file format */
  128.   status = XReadBitmapFile(XtDisplay(toplevel),
  129.                             DefaultRootWindow(XtDisplay(toplevel)),
  130.                             item->fname, &x, &y, &item->bitmap, &i, &i);
  131.   if( status == BitmapSuccess ) {
  132.     item->type = Xbm;
  133.     (void) sprintf(item->info, "\"%s\", %dx%d bitmap", item->fname, x, y);
  134.     return TRUE;
  135.   }
  136.  
  137. #ifdef DO_XPMS
  138.   /* Try a X Pixmap format */
  139.   item->attr.valuemask = XpmReturnPixels | XpmCloseness;
  140.   status = XpmReadPixmapFile(XtDisplay(toplevel),
  141.                             DefaultRootWindow(XtDisplay(toplevel)),
  142.                             item->fname, &item->bitmap,&m,&item->attr);
  143.   switch( status ) {
  144.     case XpmSuccess:
  145.       item->type = Xpm;
  146.       (void) sprintf(item->info, "\"%s\", %dx%d pixmap (%d colors)",
  147.                item->fname, item->attr.width, item->attr.height,
  148.                item->attr.npixels);
  149.       if ( m != None )
  150.         XFreePixmap(XtDisplay(toplevel), m);
  151.       return TRUE;
  152.     case XpmColorFailed:
  153.     case XpmNoMemory:
  154.       item->type = BadXpm;
  155.       if ( item->bitmap != None ) {
  156.         XFreePixmap(XtDisplay(toplevel), item->bitmap);
  157.         item->bitmap = None;
  158.       }
  159.       if ( m != None )
  160.         XFreePixmap(XtDisplay(toplevel), m);
  161.       return FALSE;
  162.    }
  163. #endif
  164.   /* Non Bitmap file */
  165.   item->type = File;    /* unknown plain file -- can't tell */
  166.   item->bitmap = None;
  167.   return 0;
  168. }
  169.  
  170.  
  171. void
  172. free_list(list)
  173. Item **list;   /* pointer to a list pointer */
  174. /* completely free all items in the given item list */
  175. {
  176.   while( *list != NULL )
  177.     *list = free_item( *list );
  178. }
  179.  
  180.  
  181. void
  182. set_label_info()
  183. /* set the contents of the label widgets information string from the
  184. ** current values of the file type counts.  NOTE: watch the string length!
  185. */
  186. {
  187. # define strend  label_info+strlen(label_info)
  188.  
  189.   label_info[0] = '\0';  /* empty the string */
  190.   if( file_counts[Xbm] > 0 )
  191.     sprintf(strend, " %d Bitmaps ",    file_counts[Xbm] );
  192.   if( file_counts[Xpm] > 0 )
  193.     sprintf(strend, " %d Pixmaps ",    file_counts[Xpm] );
  194.   if( file_counts[BadXpm] > 0 )
  195.     sprintf(strend, " %d Can't Show ", file_counts[BadXpm] );
  196.   if( file_counts[File] + file_counts[Bad]  > 0 )
  197.     sprintf(strend, " %d Unknown ",    file_counts[File] + file_counts[Bad] );
  198.   if( file_counts[Dir]-2 > 0 )
  199.     sprintf(strend, " %d Dirs ",       file_counts[Dir]-2 );
  200.  
  201.   XtVaSetValues(lw, XtNlabel, (XtArgVal)label_info, NULL);
  202. # undef strend
  203. }
  204.  
  205. /*------------------------------------------------------------------------*/
  206.  
  207. static void
  208. allocate_widgets( n )
  209. /* create enough widgets to display n bitmaps */
  210.   int n;
  211. {
  212.   char name[8];
  213.   Widget w;
  214.  
  215.   if( allocated == n ) return;   /* just right -- no need to do anthing */
  216.  
  217.   if( allocated < n ) {   /* ok allocate more widgets */
  218.  
  219.     if(widget_array == NULL) {
  220.       widget_array = (Widget *)malloc( n * sizeof(Widget) );
  221.       if( widget_array == NULL ) {
  222.         perror("xbmbrowser: malloc widget_array");
  223.         abort();
  224.       }
  225.     } else {
  226.       widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
  227.       if( widget_array == NULL ) {
  228.         perror("xbmbrowser: realloc larger widget_array");
  229.         abort();
  230.       }
  231.     }
  232.  
  233.     for( ; allocated < n; allocated++ ) {
  234.    
  235.       sprintf(name, "%d", allocated);
  236.       w = XtVaCreateWidget(name, labelWidgetClass, bw, NULL);
  237.       XtOverrideTranslations(w, XtParseTranslationTable(Translations));
  238.       widget_array[allocated] = w;
  239.     }
  240.  
  241.   }
  242. #if 0
  243. /* This code will eventually cause a core dump when lots of directory
  244. ** changes are performed by the user. The problem seems to occur when
  245. ** widgets are really destroyed (they are just flaged for destruction
  246. ** below.  I can't seem to find any problem with the code below however.
  247. ** It just doesn't seem to work.
  248. */
  249.   else {  /* ok we have too many widgets -- remove about a 1/3 of them */
  250.     n = ( allocated + allocated + n ) / 3; /* the final level we want */
  251.     
  252.     for( allocated--; allocated >= n ; allocated-- )
  253.       XtDestroyWidget( widget_array[allocated] );
  254.     allocated++;
  255.  
  256.     widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
  257.     if( widget_array == NULL ) {
  258.       perror("xbmbrowser: realloc smaller widget_array");
  259.       abort();
  260.     }
  261.   }
  262.  
  263.   /* insure that allocated is now equal to n (which may be calculated above */
  264.   assert( allocated == n );
  265. #endif
  266. }
  267.  
  268. static void
  269. merge_bitmaps()
  270. /* Merge the old_file_list that is currently with the new_file_list just 
  271. ** read in. Adjust the new list to reflect any changes to the current
  272. ** directory looking for additions, deletions and modifications to the
  273. ** bitmap files.
  274. */
  275. {
  276.   Item *old_file_list;  /* the old file list that we originally had */
  277.   Item **last_ptr;      /* pointer to the last ponter in the merged list */
  278.   Item *item;           /* general item pointer */
  279.   int   count, cmp;     /* count of bitmaps, filename comparasion */
  280.  
  281.   /* first un-manage all the widgets and free the current file_list
  282.   ** This saves on multiple geometry requests while we do the work
  283.   */
  284.   if( managed > 0 ) {
  285.     XtUnmanageChildren(widget_array, managed);
  286.     managed = 0; 
  287.   }
  288.  
  289.   old_file_list = file_list;   /* make the current list old */
  290.   file_list = NULL;            /* file list (the merger) is empty */
  291.   last_ptr = &file_list;       /* point to the last pointer in empty list */
  292.  
  293.   /* zero all the file_type counts */
  294.   for( count = 0 ; count < NumFileTypes ; count++ )
  295.      file_counts[count] = 0;
  296.   count = 0;  /* count of widgets with valid bitmaps */
  297.  
  298.  
  299.   while( old_file_list != NULL && new_file_list != NULL ) {
  300.     /* items present in both lists */
  301.  
  302.     cmp = strcmp( old_file_list->fname, new_file_list->fname );
  303.     
  304.     if( cmp == 0 ) {
  305.       if ( old_file_list->mtime == new_file_list->mtime ) {
  306.  
  307.         /* NO CHANGE -- same file in both lists without any modifications */
  308.         new_file_list = free_item( new_file_list ); /* junk the new item */
  309.  
  310.     *last_ptr = item = old_file_list;  /* append old item to merged list */
  311.     last_ptr = &(item->next);          /* adjust last_ptr in merged list */
  312.     old_file_list = *last_ptr;         /* remove item from old list */
  313.     /* *last_ptr = NULL;               /* not really nessary */
  314.  
  315.     /* adjust the counts of the file types */
  316.     if( item-> bitmap != None ) count++;
  317.     file_counts[item->type]++;
  318.     continue;
  319.       }
  320.       else {
  321.         /* MODIFIED -- same file but it has been modified or replaced */
  322.         old_file_list = free_item( old_file_list );  /* junk the old item */
  323.         cmp = 1;    /* ok now pretend that the new item is a new addition */
  324.         /* FALL THROUGH */
  325.       }
  326.     }
  327.  
  328.     /* ADDITION -- a new file (or newly modified) to be added to list */
  329.     if( cmp > 0 ) {
  330.       /* a new file added to the directory -- append it to file_list */
  331.       *last_ptr = item = new_file_list;  /* append new item to merged list */
  332.       last_ptr = &(item->next);          /* adjust last_ptr in merged list */
  333.       new_file_list = *last_ptr;         /* remove item from new list */
  334.       /* *last_ptr = NULL;               /* not really nessary */
  335.  
  336.       if( item->type == File  &&  read_bitmap( item ) ) /* read in bitmap */
  337.         count++;                      /* count number of valid bitmaps */
  338.       file_counts[item->type]++;      /* count up the file types */
  339.       continue;
  340.     }
  341.  
  342.     /* DELETION -- the old file has been deleted */
  343.     if( cmp < 0 ) {
  344.       old_file_list = free_item( old_file_list ); /* delete this file */
  345.       continue;
  346.     }
  347.  
  348.     /* this point should never be reached */
  349.     /*NOTREACHED*/
  350.     assert( FALSE );
  351.   }
  352.  
  353.   /*                   --------------
  354.   ** At this point either one or both of the merging file lists
  355.   ** is empty. As such we can just finish of the merged list quickly 
  356.   */
  357.   assert( new_file_list == NULL || old_file_list == NULL );
  358.  
  359.   /* ADD any more new files in the new_file_list */
  360.  
  361.   *last_ptr = new_file_list;   /* the rest of the merged list is new */
  362.   for( item = new_file_list;  item != NULL;  item = item->next ) {
  363.     if( item->type == File  &&  read_bitmap( item ) )
  364.       count++; 
  365.     file_counts[item->type]++;
  366.   }
  367.   new_file_list = NULL;  /* new_file_list is now empty */
  368.      
  369.  
  370.   /* DELETE any old items left in the old_file_list */
  371.   free_list(&old_file_list);
  372.  
  373.   /*                   --------------
  374.   ** Merger of file lists complete. Allocate enough widgets to
  375.   ** hold the bitmaps to be displayed and display them.
  376.   */
  377.   
  378.   /* allocate/deallocate widgets as needed */
  379.   allocate_widgets( count );
  380.  
  381.   /* assign the bitmaps to the widgets in order */
  382.   managed = 0;   /* this should be zero but make sure */
  383.   for( item = file_list;  item != NULL;  item = item->next )
  384.     if( item->bitmap != None ) {
  385.       item->index = managed;
  386.       XtVaSetValues( widget_array[item->index],
  387.                        XtNbitmap, (XtArgVal)item->bitmap,
  388.                        XtNlabel,  (XtArgVal)item->info, NULL); 
  389.       managed++;
  390.     }
  391.  
  392.   /* check the result */
  393.   assert( managed == count );
  394.  
  395.   /* manage the widgets */
  396.   if( managed > 0 )
  397.     XtManageChildren(widget_array, managed);
  398. }
  399.  
  400. /*------------------------------------------------------------------------*/
  401.  
  402. void
  403. scan_bitmaps()
  404. /* scan and display all the bitmaps in the current directory */
  405. {
  406.   /* just free all the bitmaps and do a rescan which handles the
  407.   ** reading of new bitmaps perfectly fine on its own. We need
  408.   ** to unmanage them here, to avoid problems.
  409.   */
  410.   if( managed > 0 ) {
  411.     XtUnmanageChildren(widget_array, managed);
  412.     managed = 0;
  413.   }
  414.   free_list(&file_list);
  415.   rescan_bitmaps();
  416. }
  417.  
  418. void
  419. rescan_bitmaps()
  420. /* Do a fast rescan and merger of the bitmaps in the current directory.
  421. ** The goal is to avoid re-reading files which were never changed.
  422. */
  423. {
  424.   assert( new_file_list == NULL );
  425.   new_file_list = get_files("."); /* the items in the current directory */
  426.   build_dirMenu();                /* build the directory menu from new list */
  427.   merge_bitmaps();                /* merge any changes into file_list */
  428.   set_label_info();               /* show the file counts being displayed */
  429.  
  430.   if( new_file_list != NULL ) {
  431.     fprintf(stderr, "xbmbrowser: bad new_file_list in rescan_bitmaps\n");
  432.     abort();
  433.   }
  434. }
  435.  
  436.